package com.health.appoint.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.health.appoint.mapper.AppointMapper;
import com.health.appoint.mapper.ScheduleMapper;
import com.health.appoint.model.appoint.AddAppointRequest;
import com.health.appoint.model.appoint.GetAppointRequest;
import com.health.appoint.model.appoint.GetMyAppointRequest;
import com.health.appoint.model.appoint.TakeAppointRequest;
import com.health.appoint.model.entity.Appoint;
import com.health.appoint.model.vo.AppointVO;
import com.health.appoint.service.AppointService;
import com.health.common.common.ErrorCode;
import com.health.common.exception.BusinessException;
import com.health.common.service.util.SDKUtils;
import jakarta.annotation.Resource;
import org.fisco.bcos.sdk.v3.model.TransactionReceipt;
import org.fisco.bcos.sdk.v3.transaction.manager.AssembleTransactionProcessor;
import org.fisco.bcos.sdk.v3.transaction.model.dto.CommonResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;

import static com.health.common.constant.ContractConstants.*;

/**
 * @author zhexueqi
 * @description 针对表【appoint(预约挂号表)】的数据库操作Service实现
 * @createDate 2024-08-21 22:03:23
 */
@Service
public class AppointServiceImpl extends ServiceImpl<AppointMapper, Appoint>
        implements AppointService {

    @Resource
    private SDKUtils sdkUtils;

    @Resource
    private ScheduleMapper scheduleMapper;

    @Value("${system.contract.contractName}")
    private String CONTRACT_NAME;
    @Value("${system.contract.address}")
    private String CONTRACT_ADDRESS;
    @Value("${system.contract.abi}")
    private String abi;
    @Value("${system.contract.bin}")
    private String bin;

    @Override
    public Boolean addAppoint(AddAppointRequest appointRequest) throws Exception {

        AssembleTransactionProcessor sdk = sdkUtils.transactionProcessor(appointRequest.getPrivateKey());
        List<Object> funcParams = new ArrayList<>();
        funcParams.add(appointRequest.getAppointId());
        funcParams.add(appointRequest.getPatientAddress());
        funcParams.add(appointRequest.getDoctorAddress());
        funcParams.add(appointRequest.getHospitalAddress());
        long timestamp = appointRequest.getAppointTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        funcParams.add(timestamp);
        CommonResponse transactionResponse = sdk.sendTransactionAndGetResponseByContractLoader(CONTRACT_NAME, CONTRACT_ADDRESS, ADD_APPOINT, funcParams);

        isSuccess(transactionResponse);
        Appoint appoint = new Appoint();

        BeanUtils.copyProperties(appointRequest, appoint);
        boolean save = save(appoint);
        if (!save) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }

        return true;
    }

    @Override
    public Boolean takeAppoint(TakeAppointRequest appointRequest) throws Exception {
        AssembleTransactionProcessor sdk = sdkUtils.transactionProcessor(appointRequest.getPrivateKey());
        List<Object> funcParams = new ArrayList<>();
        funcParams.add(appointRequest.getAppointId());
        funcParams.add(appointRequest.getPatientAddress());
        CommonResponse transactionResponse = sdk.sendTransactionAndGetResponseByContractLoader(CONTRACT_NAME, CONTRACT_ADDRESS, TAKE_APPOINT, funcParams);

        return isSuccess(transactionResponse);
    }

    @Override
    public AppointVO getAppoint(GetAppointRequest getAppointRequest) throws Exception {
        AssembleTransactionProcessor sdk = sdkUtils.transactionProcessor(getAppointRequest.getPrivateKey());
        List<Object> funcParams = new ArrayList<>();
        funcParams.add(getAppointRequest.getAppointId());
        funcParams.add(getAppointRequest.getPatientAddress());
        TransactionReceipt transactionReceipt = sdk.sendTransactionAndGetReceiptByContractLoader(CONTRACT_NAME, CONTRACT_ADDRESS, GET_APPOINT, funcParams);
        String res = transactionReceipt.getOutput();
        JSONArray jsonArray = JSONArray.parseArray(res);
        if (jsonArray.isEmpty()) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        res = jsonArray.getString(0);
        jsonArray = JSONArray.parseArray(res);

        Appoint appoint = getById(getAppointRequest.getAppointId());
        if (appoint == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }


        return AppointVO.builder()
                .id(getAppointRequest.getAppointId())
                .patientAddress(jsonArray.getString(0))
                .doctorAddress(jsonArray.getString(1))
                .hospitalName(appoint.getHospitalName())
                .status(Integer.valueOf(jsonArray.getString(3)))
                .createTime(appoint.getCreateTime()).build();
    }

    @Override
    public Page<AppointVO> getMyAppoint(GetMyAppointRequest getMyAppointRequest) {
        QueryWrapper<Appoint> query = new QueryWrapper<>();
        query.eq("patient_address", getMyAppointRequest.getPatientAddress());
        query.eq("status", getMyAppointRequest.getStatus());
        Page<Appoint> page1 = page(new Page<>(getMyAppointRequest.getPageNum(), getMyAppointRequest.getPageSize()), query);
        List<Appoint> records = page1.getRecords();
        if (records.isEmpty()) {
            return Page.of(1, 10);
        }
        List<AppointVO> collect = records.stream().map(appoint -> AppointVO.builder()
                .id(appoint.getId())
                .patientAddress(appoint.getPatientAddress())
                .doctorAddress(appoint.getDoctorAddress())
                .hospitalName(appoint.getHospitalName())
                .status(appoint.getStatus())
                .createTime(appoint.getCreateTime())
                .departmentName(appoint.getDepartment())
               .timeSlot(appoint.getTimeSlot()).build()).toList();
        //把collect塞进page的record中
        Page<AppointVO> page = Page.of(page1.getCurrent(), page1.getSize(), page1.getTotal(), page1.searchCount());
        page.setRecords(collect);
        return page;
    }


    /**
     * 判断是否成功
     *
     * @param transactionResponse
     */
    private Boolean isSuccess(CommonResponse transactionResponse) {
        String returnMessage = transactionResponse.getReturnMessage();
        if (!returnMessage.equalsIgnoreCase("success")) {
            throw new BusinessException(ErrorCode.CONTRACT_ERROR);
        }
        return true;
    }
}




